package com.wjc.train.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wjc.train.business.entity.DailyTrain;
import com.wjc.train.business.entity.DailyTrainTicket;
import com.wjc.train.business.entity.TrainStation;
import com.wjc.train.business.enums.SeatTypeEnum;
import com.wjc.train.business.enums.TrainTypeEnum;
import com.wjc.train.business.repository.DailyTrainTicketRepository;
import com.wjc.train.business.repository.TrainStationRepository;
import com.wjc.train.business.req.DailyTrainTicketQueryReq;
import com.wjc.train.business.req.DailyTrainTicketSaveReq;
import com.wjc.train.business.resp.DailyTrainTicketQueryResp;
import com.wjc.train.business.service.IDailyTrainSeatService;
import com.wjc.train.business.service.IDailyTrainTicketService;
import com.wjc.train.common.enums.LogicEnum;
import com.wjc.train.common.untils.CopyUtil;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * <p>
 * 余票信息 服务实现类
 * </p>
 *
 * @author Guessed
 * @since 2023-08-11
 */
@Service
@Slf4j
public class DailyTrainTicketServiceImpl  implements IDailyTrainTicketService {

    @Resource
    private DailyTrainTicketRepository dailytrainticketRepository;

    @Resource
    private TrainStationRepository trainstationRepository;

    @Resource
    private IDailyTrainSeatService dailyTrainSeatService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(DailyTrainTicketSaveReq dailytrainticketSaveReq) {
        DailyTrainTicket dailytrainticket = CopyUtil.copy(dailytrainticketSaveReq, DailyTrainTicket.class);
        dailytrainticketRepository.saveOrUpdate(dailytrainticket);
    }

    @Override
    public IPage<DailyTrainTicketQueryResp> queryList(IPage<DailyTrainTicketQueryResp> page, DailyTrainTicketQueryReq dailytrainticketQueryReq) {
        //添加缓存
        //组装key
        String key = buildKey(dailytrainticketQueryReq);
        String value = stringRedisTemplate.opsForValue().get(key);
        if(StringUtils.isNotBlank(value)){
            log.info("余票查询命中缓存");
            log.info("redisVal：{}",value);
            JSONArray objects = JSON.parseArray(value);
            List<DailyTrainTicketQueryResp> list  = objects.toJavaList(DailyTrainTicketQueryResp.class);
            IPage<DailyTrainTicketQueryResp> redisPage = new Page<>();
            redisPage.setRecords(list);
            redisPage.setTotal(list.get(0).getTotal());
            return redisPage;
        }else {
            IPage<DailyTrainTicketQueryResp> iPage = dailytrainticketRepository.queryList(page, dailytrainticketQueryReq);
            List<DailyTrainTicketQueryResp> records = iPage.getRecords();
            if(CollectionUtil.isNotEmpty(records)){
                //放入缓存
                log.info("余票查询放入缓存");
                records.forEach(x-> x.setTotal((int) iPage.getTotal()));
                String jsonString = JSON.toJSONString(records);
                stringRedisTemplate.opsForValue().set(key,jsonString, Duration.ofSeconds(30));
            }
            return iPage;
        }
    }

    private String buildKey(DailyTrainTicketQueryReq dailytrainticketQueryReq){
        //分页数据,查询参数:车次编码、日期、出发站、到达站
        StringJoiner sj = new StringJoiner(":","tickets","");
        String queryPage = dailytrainticketQueryReq.getQueryPage().toString();
        sj.add(queryPage);
        String trainCode = dailytrainticketQueryReq.getTrainCode();
        Date date = dailytrainticketQueryReq.getDate();
        String start = dailytrainticketQueryReq.getStart();
        String end = dailytrainticketQueryReq.getEnd();
        if(ObjectUtil.isNotEmpty(trainCode)){
            sj.add(trainCode);
        }
        if(ObjectUtil.isNotEmpty(date)){
            sj.add(date.toString());
        }
        if(ObjectUtil.isNotEmpty(start)){
            sj.add(start);
        }
        if(ObjectUtil.isNotEmpty(end)){
            sj.add(end);
        }
        log.info("ticketsKey: {}",sj.toString());
        return sj.toString();
    }

    @Override
    public void delete(Long id) {
        dailytrainticketRepository.getBaseMapper().deleteById(id);
    }

    @Override
    @Transactional(rollbackFor=Exception.class)
    public void genDaily(DailyTrain dailyTrain,Date date, String trainCode) {
        log.info("开始生成日期:{},车次:{}的车票信息", DateUtil.formatDate(date),trainCode);
        //查询当日车票信息并删除
        List<DailyTrainTicket> trainTicketList = dailytrainticketRepository.lambdaQuery()
                .eq(DailyTrainTicket::getDate, date)
                .eq(DailyTrainTicket::getIsDeleted, LogicEnum.NOT_DELETED.getCode())
                .eq(DailyTrainTicket::getTrainCode, trainCode).list();
        if(CollectionUtil.isNotEmpty(trainTicketList)){
            List<Long> collect = trainTicketList.stream().map(DailyTrainTicket::getId).collect(Collectors.toList());
            dailytrainticketRepository.getBaseMapper().deleteBatchIds(collect);
        }
        //查询车站信息
        //查询该车次的所有车站信息
        List<TrainStation> trainStationList = trainstationRepository.lambdaQuery()
                .eq(TrainStation::getTrainCode, trainCode)
                .eq(TrainStation::getIsDeleted, LogicEnum.NOT_DELETED.getCode()).list();
        if(CollectionUtil.isEmpty(trainStationList)){
            log.error("该车次不存在车站信息，车次编号为:{}",trainCode);
            return;
        }
        //查询各类型总数
        int ywCount = dailyTrainSeatService.countSeat(date, trainCode, SeatTypeEnum.YW.getCode());
        int rwCount = dailyTrainSeatService.countSeat(date, trainCode, SeatTypeEnum.RW.getCode());
        int ydzCount = dailyTrainSeatService.countSeat(date, trainCode, SeatTypeEnum.YDZ.getCode());
        int edzCount = dailyTrainSeatService.countSeat(date, trainCode, SeatTypeEnum.EDZ.getCode());

        //获得该车次类型
        String trainType = dailyTrain.getType();
        BigDecimal priceRate = EnumUtil.getFieldBy(TrainTypeEnum::getPriceRate, TrainTypeEnum::getCode, trainType);

        List<DailyTrainTicket> saveList = new ArrayList<>();
        //循环得到出发站
        for (int i = 0; i < trainStationList.size(); i++) {
            TrainStation trainStationStart = trainStationList.get(i);
            BigDecimal sumKm = BigDecimal.ZERO;
            //得到终点站
            for (int j = i+1; j < trainStationList.size(); j++) {
                TrainStation trainStationEnd = trainStationList.get(j);
                //计算里程之和
                 sumKm = sumKm.add(trainStationEnd.getKm());

                DailyTrainTicket dailyTrainTicket = new DailyTrainTicket();
                dailyTrainTicket.setDate(date);
                dailyTrainTicket.setTrainCode(trainCode);
                dailyTrainTicket.setStart(trainStationStart.getName());
                dailyTrainTicket.setStratPinyin(trainStationStart.getNamePinyin());
                dailyTrainTicket.setStartTime(trainStationStart.getOutTime());
                dailyTrainTicket.setStartIndex(ByteUtil.intToByte(trainStationStart.getIndex()));
                dailyTrainTicket.setEnd(trainStationEnd.getName());
                dailyTrainTicket.setEndPinyin(trainStationEnd.getNamePinyin());
                dailyTrainTicket.setEndTime(trainStationEnd.getInTime());
                dailyTrainTicket.setEndIndex(ByteUtil.intToByte(trainStationEnd.getIndex()));
                dailyTrainTicket.setYw(ywCount);
                //票价 = 里程之和 * 座位单价 * 车次类型系数
                BigDecimal ydzPrice = sumKm.multiply(SeatTypeEnum.YDZ.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal edzPrice = sumKm.multiply(SeatTypeEnum.EDZ.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal rwPrice = sumKm.multiply(SeatTypeEnum.RW.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal ywPrice = sumKm.multiply(SeatTypeEnum.YW.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                dailyTrainTicket.setYwPrice(ywPrice);
                dailyTrainTicket.setEdz(edzCount);
                dailyTrainTicket.setEdzPrice(edzPrice);
                dailyTrainTicket.setYdz(ydzCount);
                dailyTrainTicket.setYdzPrice(ydzPrice);
                dailyTrainTicket.setRw(rwCount);
                dailyTrainTicket.setRwPrice(rwPrice);
                saveList.add(dailyTrainTicket);
            }
        }
        dailytrainticketRepository.saveBatch(saveList);

        log.info("结束生成日期:{},车次:{}的车票信息", DateUtil.formatDate(date),trainCode);

    }
}
